home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Classes / 2.0_nxyPalette1.2 / src / Plot.m < prev    next >
Encoding:
Text File  |  1992-05-18  |  20.0 KB  |  715 lines

  1.  
  2. /* Generated by Interface Builder */
  3.  
  4. #import "Plot.h"
  5. #import "NXYView.h"        /*  only for initializeLegendBox */
  6. #import <appkit/Matrix.h>
  7. #import <appkit/Cell.h>
  8. #import <math.h>
  9. #import <appkit/OpenPanel.h>
  10. #import <appkit/publicWraps.h>  //  For NXBeep (from 1.7)
  11.  
  12. #define ALLOCSIZE 2048        /* used in malloc in readData */
  13.  
  14. //Added for 1.7 functions
  15. int beepError=0;
  16.  
  17. // Added from nxyplot 1.7
  18. /* The following routines are in auxil.m: */
  19. extern void computeNiceLinInc(float *, float *, float *);
  20. extern void computeNiceLogInc(float *, float *, float *);
  21.  
  22.  
  23.  
  24. @implementation Plot
  25.  
  26. - (NXCoord *)xdata  { return x;}
  27. - (NXCoord **)ydata { return y;}
  28.  
  29. - (int)nPoints    { return npoints;}
  30. - (int)nCurves    { return ncurves;}
  31.  
  32. //- (const char *)provideXtitle 
  33. //   {return [xTitle stringValueAt:0];}
  34. //   {return [canvas xaxisLabel];}
  35. //- (const char *)provideYtitle  
  36. //  {return [yTitle stringValueAt:0];}
  37.  // {return [canvas yaxisLabel];}
  38. //- (const char *)provideMaintitle 
  39. // {return [mainTitle stringValueAt:0];}
  40.  //{return [canvas mainTitle];}
  41.  
  42. - (BOOL) shouldDrawGrid
  43. {
  44. //  if ( [gridOnOff state] ) return YES;
  45.   if ( [canvas gridState] ) return YES;
  46.   else return NO;
  47. }
  48.  
  49. - (BOOL) shouldDrawBox
  50. {
  51. //  if ( [borderBoxOnOff state] ) return YES;
  52.   if ( [canvas borderState] ) return YES;
  53.   else return NO;
  54. }
  55.  
  56.  
  57. - (BOOL) xaxisLog
  58. {
  59. //  if ( [xLinLog state] ) return YES;
  60.     if([canvas xLinLogState]) return YES;
  61.   else return NO;
  62. }
  63.  
  64. - forceXaxisLinear
  65. {
  66. //  [xLinLog setState:0];
  67. //  [xLinLog display];
  68.     [canvas setXLinLogState:LINEAR];
  69.   return self;
  70. }
  71.  
  72. - (BOOL) yaxisLog
  73. {
  74. //  if ( [yLinLog state] ) return YES;
  75.     if([canvas yLinLogState]) return YES;
  76.   else return NO;
  77. }
  78.  
  79. - forceYaxisLinear
  80. {
  81. //  [yLinLog setState:0];
  82. //  [yLinLog display];
  83.     [canvas setYLinLogState:LINEAR];
  84.   return self;
  85. }
  86.  
  87. - (int)providelinestyle:(int)aCurve
  88. {
  89.       return 0;            /* for safety */
  90. }
  91.  
  92. - (int)providesymbolstyle:(int)aCurve
  93. {
  94.       return 0;            /* for safety */
  95. }
  96.  
  97. - (int)providesymbolsize{  return 0;}
  98. - (int)providelinethickness{  return 0;}
  99.  
  100. //- (float)provideXmin  {return [xMin floatValueAt:0];}
  101. - (float)provideXmin  {return [canvas xMinValue];}
  102. //- (float)provideXmax  {return [xMax floatValueAt:0];}
  103. - (float)provideXmax  {return [canvas xMaxValue];}
  104. //- (float)provideXinc  {return [xInc floatValueAt:0];}
  105. - (float)provideXinc  {return [canvas xIncValue];}
  106. //- (float)provideYmin  {return [yMin floatValueAt:0];}
  107. - (float)provideYmin  {return [canvas yMinValue];}
  108. //- (float)provideYmax  {return [yMax floatValueAt:0];}
  109. - (float)provideYmax  {return [canvas yMaxValue];}
  110. //- (float)provideYinc  {return [yInc floatValueAt:0];}
  111. - (float)provideYinc  {return [canvas yIncValue];}
  112.  
  113. //- resetXmin:(float)aNum { [xMin setFloatValue:aNum at:0]; return self; }
  114. - resetXmin:(float)aNum { [canvas setXminValue:aNum]; return self; }
  115. //- resetXmax:(float)aNum { [xMax setFloatValue:aNum at:0]; return self; }
  116. - resetXmax:(float)aNum { [canvas setXmaxValue:aNum]; return self; }
  117. //- resetXinc:(float)aNum { [xInc setFloatValue:aNum at:0]; return self; }
  118. - resetXinc:(float)aNum { [canvas setXincValue:aNum]; return self; }
  119. //- resetYmin:(float)aNum { [yMin setFloatValue:aNum at:0]; return self; }
  120. - resetYmin:(float)aNum { [canvas setYminValue:aNum]; return self; }
  121. //- resetYmax:(float)aNum { [yMax setFloatValue:aNum at:0]; return self; }
  122. - resetYmax:(float)aNum { [canvas setYmaxValue:aNum]; return self; }
  123. //- resetYinc:(float)aNum { [yInc setFloatValue:aNum at:0]; return self; }
  124. - resetYinc:(float)aNum { [canvas setYincValue:aNum]; return self; }
  125.  
  126. - drawPlot:sender
  127. {
  128. //    if (!x) return self;
  129.  
  130.   [self sanityCheck];        /* disallow various bad parameters */
  131.     [canvas display];
  132.     return self;
  133. }
  134.  
  135. // Allocate enough memory and read the data points
  136. /*
  137.  * WARNING: This code will go into an infinite loop if there is illegal
  138.  * crud in the data file (such as a comma, for example).  The culprit is
  139.  * the "fscanf" below; we will put up with this for now, but we should
  140.  * make this more robust.
  141.  */
  142. - (int) readDataFromFile:(FILE *)aDataStream
  143. {
  144.     BOOL    inword = NO;
  145.     char    c;
  146.     int     j, size = ALLOCSIZE;
  147. //    int     oldncurves = ncurves; /* for linestyle matrix column deleting */
  148.  
  149.     NXPing();            /* Probably not needed now--was for Plot Button */
  150.  
  151.     /* First, free x and y here if there's already data in them */
  152.     if (x) {
  153.       free( (void *)x );
  154.       for (j = 0; j < ncurves; j++) {
  155.     free( (void *)(*(y+j)) );
  156.       }
  157.       free( (void *)y );
  158.     }
  159.  
  160.     /* Figure out the number of curves in the file by reading characters  */
  161.     /* until a newline is encountered; the number of curves is one less   */
  162.     /* than the number of words found.                                    */
  163.     /* For now we assume the input file is an ascii file.                 */
  164.     ncurves = -1;
  165.     while (1) {
  166.       c = getc(aDataStream);
  167.       if (c == '\n') {
  168.     break;            /* breaks out of while loop */
  169.       }
  170.       if ((inword==NO) && !(c==' ' || c=='\t')) {
  171.     ncurves++;
  172.     inword = YES;
  173.       }
  174.       if ((inword==YES) && (c==' ' || c=='\t')) {
  175.     inword = NO;
  176.       }
  177.     }
  178.     if (ncurves == -1) {    /* couldn't find "\n", give up */
  179.       return 0;
  180.     }
  181.  
  182.     /* Now read the data into memory */
  183.     rewind(aDataStream);
  184.     
  185.     y = (NXCoord **)malloc( ncurves * sizeof(NXCoord *) );
  186.     x = (NXCoord *)malloc( size * sizeof(NXCoord) );
  187.     for (j = 0; j < ncurves; j++) {
  188.       *(y+j) = (NXCoord *)malloc( size * sizeof(NXCoord) );
  189.     }
  190.     npoints = 0;
  191.     while(1) {
  192.       if( (fscanf(aDataStream, "%f", x+npoints)) == EOF ) {
  193.     break;            /* breaks out of the while loop */
  194.       }
  195.       for (j = 0; j < ncurves; j++) {
  196.     fscanf(aDataStream, "%f", *(y+j)+npoints);
  197.       }
  198.       npoints++;
  199.       if (npoints == size) {        /* get more memory */
  200.     size += ALLOCSIZE;
  201.     x = (NXCoord *)realloc(x, size * sizeof(NXCoord));
  202.     for (j = 0; j < ncurves; j++) {
  203.       *(y+j) = (NXCoord *)realloc( *(y+j), size * sizeof(NXCoord) );
  204.     }
  205.       }      
  206.     }
  207.  
  208.      return npoints;
  209. }
  210.  
  211. // Following was added by cwf. It is just the above method modified for a NXStream
  212. // This should be replaced by the equivalent code from nxyplot1.7
  213. /*
  214.  * WARNING: This code will go into an infinite loop if there is illegal
  215.  * crud in the data file (such as a comma, for example).  The culprit is
  216.  * the "fscanf" below; we will put up with this for now, but we should
  217.  * make this more robust.
  218.  */
  219. - (int) readDataFromStream:(NXStream *)aDataStream;
  220. {
  221.     BOOL    inword = NO;
  222.     char    c;
  223.     int     j, size = ALLOCSIZE;
  224. //    int     oldncurves = ncurves; /* for linestyle matrix column deleting */
  225.  
  226.     NXPing();            /* Probably not needed now--was for Plot Button */
  227.  
  228.     /* First, free x and y here if there's already data in them */
  229.     if (x) {
  230.       free( (void *)x );
  231.       for (j = 0; j < ncurves; j++) {
  232.     free( (void *)(*(y+j)) );
  233.       }
  234.       free( (void *)y );
  235.     }
  236.  
  237.     /* Figure out the number of curves in the file by reading characters  */
  238.     /* until a newline is encountered; the number of curves is one less   */
  239.     /* than the number of words found.                                    */
  240.     /* For now we assume the input file is an ascii file.                 */
  241.     ncurves = -1;
  242.     while (1) {
  243.       c = NXGetc(aDataStream);
  244.       if (c == '\n') {
  245.     break;            /* breaks out of while loop */
  246.       }
  247.       if ((inword==NO) && !(c==' ' || c=='\t')) {
  248.     ncurves++;
  249.     inword = YES;
  250.       }
  251.       if ((inword==YES) && (c==' ' || c=='\t')) {
  252.     inword = NO;
  253.       }
  254.     }
  255.     if (ncurves == -1) {    /* couldn't find "\n", give up */
  256.       return 0;
  257.     }
  258.  
  259.     /* Now read the data into memory */
  260.     NXSeek(aDataStream,0L,NX_FROMSTART);
  261.     
  262.     y = (NXCoord **)malloc( ncurves * sizeof(NXCoord *) );
  263.     x = (NXCoord *)malloc( size * sizeof(NXCoord) );
  264.     for (j = 0; j < ncurves; j++) {
  265.       *(y+j) = (NXCoord *)malloc( size * sizeof(NXCoord) );
  266.     }
  267.     npoints = 0;
  268.     while(1) {
  269.       if( (NXScanf(aDataStream, "%f", x+npoints)) == EOF ) {
  270.     break;            /* breaks out of the while loop */
  271.       }
  272.       for (j = 0; j < ncurves; j++) {
  273.     NXScanf(aDataStream, "%f", *(y+j)+npoints);
  274.       }
  275.       npoints++;
  276.       if (npoints == size) {        /* get more memory */
  277.     size += ALLOCSIZE;
  278.     x = (NXCoord *)realloc(x, size * sizeof(NXCoord));
  279.     for (j = 0; j < ncurves; j++) {
  280.       *(y+j) = (NXCoord *)realloc( *(y+j), size * sizeof(NXCoord) );
  281.     }
  282.       }      
  283.     }
  284.  
  285.      return npoints;
  286. }
  287.  
  288.  
  289. /* Might want to make sure INLINE_MATH is defined when math.h is included */
  290.  
  291. - checkLinLog
  292. {
  293.   /* Check x and y axes -- do a heuristic test for log/lin.
  294.    * The test employed comes from M. Merriam and xyplot.
  295.    */
  296.   double    scale, linsum, logsum;
  297.   register  double tmp;
  298.   int       i, j;
  299.  
  300.   /* First test x axis.  */
  301.   if (datamax.x > 0.0  &&  datamin.x > 0.0  && datamax.x != datamin.x) {
  302.     scale = fabs( (double)datamax.x - (double)datamin.x );
  303.     linsum = 0.0;
  304.     for (j=1; j<npoints; j++) {
  305.       tmp = ( (double)x[j]-(double)x[j-1] )/(double)scale; /* avoid overflow */
  306.       linsum += tmp*tmp;
  307.     }
  308.     scale = log10( (double)datamax.x/(double)datamin.x );
  309.                 /* what if datamax.x<datamin.x? */
  310.     logsum = 0.0;
  311.     for (i=1; i<npoints; i++) {
  312.       tmp = log10( (double)x[i]/(double)x[i-1] ) / scale;
  313.       logsum += tmp*tmp;
  314.     }
  315.     if (linsum < logsum) {
  316. //      [xLinLog setState:0];    /* linear axis */
  317.     [canvas setXLinLogState:LINEAR];
  318.     }
  319.     else {
  320. //      [xLinLog setState:1];    /* logarithmic axis */
  321.     [canvas setXLinLogState:LOG];      
  322.     }
  323.   }
  324.   else {
  325. //    [xLinLog setState:0];    /* linear */
  326.     [canvas setXLinLogState:LINEAR];    
  327.   }
  328.   /* Now test y axis */
  329.   if (datamax.y > 0.0  &&  datamin.y > 0.0  && datamax.y != datamin.y) {
  330.     scale = fabs( (double)datamax.y - (double)datamin.y );
  331.     linsum = 0.0;
  332.     for (j=0; j<ncurves; j++) {
  333.       for (i=1; i<npoints; i++) {
  334.     tmp = ( (double)*(*(y+j)+i) - (double)*(*(y+j)+i-1) )
  335.                         / scale; /* avoid overflow */
  336.     linsum += tmp*tmp;
  337.       }
  338.     }
  339.     scale = log10((double)datamax.y/(double)datamin.y);
  340.                 /* what if datamax.y<datamin.y? */
  341.     logsum = 0.0;
  342.     for (j=0; j<ncurves; j++) {
  343.       for (i=1; i<npoints;i++) {
  344.     tmp = log10( (double)*(*(y+j)+i)/(double)*(*(y+j)+i-1) ) / scale;
  345.     logsum += tmp*tmp;
  346.       }
  347.     }
  348.     if (linsum < logsum) {
  349. //      [yLinLog setState:0];    /* linear axis */
  350.     [canvas setYLinLogState:LINEAR];
  351.     }
  352.     else {
  353. //      [yLinLog setState:1];    /* logarithmic axis */
  354.     [canvas setYLinLogState:LOG];
  355.     }
  356.   }
  357.   else {
  358. //    [yLinLog setState:0];    /* linear */
  359.     [canvas setYLinLogState:LINEAR];
  360.   }
  361. //  [xLinLog display];
  362. //  [yLinLog display];
  363.   return self;
  364. }
  365.  
  366. // Go through the data set and find values for datamin.x,
  367. // datamax.x, datamin.y, datamax.y
  368. - findMinAndMax
  369. {
  370.     if (x)  {
  371.       int    i, j;
  372.       datamin.x = datamax.x = x[0];
  373.       for (i = 1; i < npoints; i++)  {
  374.     if (x[i] < datamin.x)
  375.       datamin.x = x[i];
  376.     else if (x[i] > datamax.x)
  377.       datamax.x = x[i];
  378.       }
  379.       datamin.y = datamax.y = *(*(y+0)+0);
  380.       for (j = 0; j < ncurves; j++) {
  381.     for (i = 0; i < npoints; i++) {
  382.       if (*(*(y+j)+i) < datamin.y)
  383.         datamin.y = *(*(y+j)+i);
  384.       else if (*(*(y+j)+i) > datamax.y)
  385.         datamax.y = *(*(y+j)+i);
  386.     }
  387.       }
  388.     }
  389. // reset min and max here (may want to change the placement of this)
  390. //    [self resetXmin:datamin.x];
  391.  //   [self resetXmax:datamax.x];
  392. //    [self resetXinc:(datamax.x - datamin.x)/5.0];
  393. //    [self resetYmin:datamin.y];
  394. //    [self resetYmax:datamax.y];
  395. //    [self resetYinc:(datamax.y - datamin.y)/5.0];
  396.  
  397.     return self;
  398. }
  399.  
  400. // Added from nxyplot 1.7
  401. // Get pleasing values for the min, max, and increments
  402. - niceMinMaxInc
  403. {
  404.   float fmin, fmax, finc;
  405.  
  406.   fmin = datamin.x;
  407.   fmax = datamax.x;
  408.   if ([self xaxisLog] ) {
  409.     computeNiceLogInc(&fmin, &fmax, &finc);
  410.   }
  411.   else {
  412.     computeNiceLinInc(&fmin, &fmax, &finc);
  413.   }
  414.   [self resetXmin:fmin];
  415.   [self resetXmax:fmax];
  416.   [self resetXinc:finc];
  417.  
  418.   fmin = datamin.y;
  419.   fmax = datamax.y;
  420.   if ([self yaxisLog] ) {
  421.     computeNiceLogInc(&fmin, &fmax, &finc);
  422.   }
  423.   else {
  424.     computeNiceLinInc(&fmin, &fmax, &finc);
  425.   }
  426.   [self resetYmin:fmin];
  427.   [self resetYmax:fmax];
  428.   [self resetYinc:finc];
  429.   return self;
  430. }
  431.  
  432. //Added from nxyplot 1.7 (Beep code "removed" for now)
  433. // We make the plotParam object responsible for checking parameters
  434. // before the PlotView object is called.  Thus the PlotView object can
  435. // assume the parameters are OK, and it doesn't have to do any checking.
  436. // Things to check: xinc has the same sign as xmax-xmin (same for y);
  437. // no negative data if log plot requested on x or y axis; there won't be
  438. // too many tic marks requested.
  439. - sanityCheck
  440. {
  441.   float xinc = [self provideXinc];
  442.   float xmax = [self provideXmax], xmin = [self provideXmin];
  443.   float yinc = [self provideYinc];
  444.   float ymax = [self provideYmax], ymin = [self provideYmin];
  445.   int   nticmarks;
  446.  
  447.   /* First check: no nonpositive data if logarithmic axis */
  448.   if ( [self xaxisLog] ) {
  449.     if (datamin.x <= 0.0 || xmin <= 0.0 || xmax <= 0.0) {
  450.  //     [xLinLog setState:0];    /* back to linear */
  451.      [canvas setXLinLogState:0];    //Changes above line since there is no control panel
  452.       NXBeep();            /* audible alert */
  453.       beepError = 1;
  454.     }
  455.   }
  456.   if ( [self yaxisLog] ) {
  457.     if (datamin.y <= 0.0 || ymin <= 0.0 || ymax <= 0.0) {
  458. //      [yLinLog setState:0];    /* back to linear */
  459.      [canvas setYLinLogState:0];    //Changes above line since there is no control panel      
  460.       NXBeep();            /* audible alert */
  461.       beepError = 2;
  462.     }
  463.   }
  464.   /* Second check: xinc has same sign as xmax and xmin */
  465.   if (xinc*(xmax-xmin) <= 0.0) { /* the bad case - avoid infinite loop */
  466.     if (xinc < 0.0) {        /*     in PlotView:drawSelf           */
  467.       xinc = -xinc;
  468.       [self resetXinc:xinc];
  469.       NXBeep();
  470.       beepError = 3;
  471.     }
  472.     if (xmax <= xmin) {
  473.       [self niceMinMaxInc];
  474.       NXBeep();            /* alert */
  475.       beepError = 4;
  476.     }
  477.   }
  478.   /* And similarly for yinc */
  479.   if (yinc*(ymax-ymin) <= 0.0) { /* the bad case - avoid infinite loop */
  480.     if (yinc < 0.0) {
  481.       yinc = -yinc;
  482.       [self resetYinc:yinc];
  483.       NXBeep();            /* alert */
  484.       beepError = 5;
  485.     }
  486.     if (ymax <= ymin) {
  487.       [self niceMinMaxInc];
  488.       NXBeep();            /* alert */
  489.       beepError = 6;
  490.     }
  491.   }
  492.   /* Third check: no more than 100 (say) tic marks on either axis */
  493.   if ( ![self xaxisLog] ) {    /*  linear axis */
  494.     nticmarks = (int) ((xmax - xmin) / xinc) ;
  495.     if (nticmarks > 100) {
  496.       computeNiceLinInc(&xmin, &xmax, &xinc);
  497.       [self resetXmin:xmin];
  498.       [self resetXmax:xmax];
  499.       [self resetXinc:xinc];
  500.       NXBeep();            /* alert */
  501. //      beepError = 7;
  502.     }
  503.   }
  504.   if ( ![self yaxisLog] ) {    /*  linear axis */
  505.     nticmarks = (int) ((ymax - ymin) / yinc) ;
  506.     if (nticmarks > 100) {
  507.       computeNiceLinInc(&ymin, &ymax, &yinc);
  508.       [self resetYmin:ymin];
  509.       [self resetYmax:ymax];
  510.       [self resetYinc:yinc];
  511.       NXBeep();            /* alert */
  512.       beepError = 8;
  513.     }
  514.   }
  515.   // This check not implemented in palette
  516.   /* Another check: the axes should be in the frame box. */
  517. //  if ([self shouldDrawAxes] && (ymin>0.0 || ymax<0.0 || xmin>0.0 || xmax<0.0)) {
  518. //    NXBeep();
  519. //    beepError = 14;        /* this is only a warning message */
  520. //  }
  521.  
  522.   return self;
  523. }
  524.  
  525. // The next method (whyTheBeep) was added from 1.7, but must be implemented by the user
  526. // Look for the key words "NXBeep()" and "beepError", some have been commented out
  527. - whyTheBeep:sender
  528. {
  529.   switch(beepError) {
  530.   case 0:
  531.     NXRunAlertPanel("The Beep Panel", "Press this button if the program beeps\n"
  532.        "and you want to know why", "OK", NULL, NULL);
  533.     break;
  534.   case 1:
  535.     NXRunAlertPanel("The Beep Happened Because:",
  536.             "x-axis changed from log to linear", "OK", NULL, NULL);
  537.     break;
  538.   case 2:
  539.     NXRunAlertPanel("The Beep Happened Because:",
  540.             "y-axis changed from log to linear", "OK", NULL, NULL);
  541.     break;
  542.   case 3:
  543.     NXRunAlertPanel("The Beep Happened Because:",
  544.             "x-increment was negative\n (I changed it)", "OK", NULL, NULL);
  545.     break;
  546.   case 4:
  547.     NXRunAlertPanel("The Beep Happened Because:",
  548.             "xmax was less than xmin\n (I changed them)", "OK", NULL, NULL);
  549.     break;
  550.   case 5:
  551.     NXRunAlertPanel("The Beep Happened Because:",
  552.             "y-increment was negative\n (I changed it)", "OK", NULL, NULL);
  553.     break;
  554.   case 6:
  555.     NXRunAlertPanel("The Beep Happened Because:",
  556.             "ymax was less than ymin\n (I changed them)", "OK", NULL, NULL);
  557.     break;
  558.   case 7:
  559.     NXRunAlertPanel("The Beep Happened Because:",
  560.             "Too many tic marks would have been on the x-axis\n"
  561.             " (I changed the min, max, and/or increment)",
  562.             "OK", NULL, NULL);
  563.     break;
  564.   case 8:
  565.     NXRunAlertPanel("The Beep Happened Because:",
  566.             "Too many tic marks would have been on the y-axis\n"
  567.             " (I changed the min, max, and/or increment)",
  568.             "OK", NULL, NULL);
  569.     break;
  570.   case 9:
  571.     NXRunAlertPanel("The Beep Happened Because:",
  572.             "x-axis was logarithmic but some datum was negative\n"
  573.             " (I changed x-axis to linear)", "OK", NULL, NULL);
  574.     break;
  575.   case 10:
  576.     NXRunAlertPanel("The Beep Happened Because:",
  577.             "y-axis was logarithmic but some datum was negative\n"
  578.             " (I changed y-axis to linear)", "OK", NULL, NULL);
  579.     break;
  580.   case 11:
  581.     NXRunAlertPanel("The Beep Happened Because:",
  582.             "tried to set color of a non-existent curve", "OK", NULL, NULL);
  583.     break;
  584.   case 12:
  585.     NXRunAlertPanel("The Beep Happened Because:",
  586.                     "box thickness was negative\n"
  587.                     " (I changed it to a positive number)", "OK", NULL, NULL);
  588.     break;
  589.   case 13:
  590.     NXRunAlertPanel("The Beep Happened Because:",
  591.                     "axis thickness was negative\n"
  592.                     " (I changed it to a positive number)", "OK", NULL, NULL);
  593.     break;
  594.   case 14:
  595.     NXRunAlertPanel("The Beep Happened Because:",
  596.             "axis drawing was requested and at least\n"
  597.             "one axis is outside the framing box", "OK", NULL, NULL);
  598.     break;
  599.   }
  600.   return self;
  601. }
  602.  
  603. // Use the OpenPanel object to get a filename
  604. - open:sender
  605. {
  606.     char const    *fileTypes[2] = {0,0};    // this type is all ASCII files (?)
  607. //    char const    *fileTypes[2] = {"xyp",0};
  608. //          this would be only files with an xyp extension
  609.     char    fname[1024];
  610.  
  611.     id openPanel = [OpenPanel new];
  612.     if ([openPanel runModalForTypes:fileTypes])  {
  613.       strncpy(fname, [openPanel filename], 1024);
  614.       [self openFile:fname];
  615.     }
  616.     return self;
  617. }
  618.  
  619. - openFile:(char *)dataFile
  620. {
  621.     FILE    *dataStream;
  622.  
  623.     if ((dataStream = fopen(dataFile, "r")) == NULL)  {
  624.       NXRunAlertPanel("Open", "Cannot open %s", "OK", NULL, NULL, dataFile);
  625.       return self;
  626.     }
  627.  
  628.     if ([self readDataFromFile:dataStream] == 0)  {
  629.       NXRunAlertPanel("Read", "Couldn't read any data from %s", "OK",
  630.               NULL, NULL, dataFile);
  631.       fclose(dataStream);
  632.       return self;
  633.     }
  634.     fclose(dataStream);
  635.  
  636. //    [canvas initializeLegendBox];
  637.  
  638. if([canvas autoMaxMinState] == YES)
  639. {
  640. // Get Max and Min from data
  641.    [self findMinAndMax];
  642.    [self niceMinMaxInc];
  643. }    
  644. //else
  645. // Use values set in Inspector
  646. //    [canvas setMaxMinValues];
  647.  
  648.     /* Check for linear or log on x and y axes */
  649. //    [self checkLinLog];
  650.     if([canvas autoPaperState])
  651. {
  652.         [self checkLinLog];
  653.             [self niceMinMaxInc];        
  654. }    
  655.     [self drawPlot:self];
  656.     
  657.     return self;
  658. }
  659.  
  660.  
  661. // The following was added to use a stream for data to plot which has been sent from
  662. // some controling App--this will(should) be replaced by later nxyplot (1.7) code since
  663. // it uses streams for all data plots.
  664. -useDataStreamAndPlot:(NXStream *)dataStream
  665. {
  666.     [self  readDataFromStream:dataStream];
  667.  
  668. if([canvas autoMaxMinState] == YES)
  669. {
  670.     [self findMinAndMax];
  671.     [self niceMinMaxInc];        
  672. }
  673.     /* Check for linear or log on x and y axes */
  674.     if([canvas autoPaperState])
  675.     {
  676.         [self checkLinLog];
  677.             [self niceMinMaxInc];        
  678.     }        
  679.     [self drawPlot:self];
  680.  
  681. return self;
  682. }
  683.  
  684.  
  685. //This archiving is unnecessary for the most part (canvas and ?? need to be archived,
  686. // the other instance variables could be removed.) Just here on the off chance I figure
  687. // out how to add a control panel.
  688. - read:(NXTypedStream*)stream
  689. /*
  690.  * Unarchives the PlotView.  Initializes four of the PlotView's instance variables
  691.  * to the values stored in the stream. 
  692.  */
  693. {
  694.     [super read:stream];
  695.     NXReadTypes(stream, "@", &canvas);
  696.         
  697.     return self;
  698. }
  699.  
  700. - write:(NXTypedStream*)stream
  701. /*
  702.  * Archives the PlotView by writing its important instance variables to the stream. 
  703.  */
  704. {
  705.     [super write:stream];
  706.     NXWriteTypes(stream, "@", &canvas);
  707.     
  708.     return self;
  709. }
  710.  
  711.  
  712.  
  713.  
  714. @end
  715.